/*
 * Copyright (C) 2017 Hisilicon Limited.
 *
 * This program is free software; you can redistribute it and /or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version
 */

#ifndef _DEVDRV_DEVICE_LOAD_H_
#define _DEVDRV_DEVICE_LOAD_H_

#include <linux/workqueue.h>


#define DEVDRV_HOST_FILE_PATH "/home/bios/"

#define DEVDRV_DEVICE_FILE_DTB "/home/bios/davinci_mini_dt.img"
#define DEVDRV_DEVICE_FILE_IMAGE "/home/bios/davinci_mini.image"
#define DEVDRV_DEVICE_FILE_FS "/home/bios/davinci_mini.cpio.gz"
#define DEVDRV_DEVICE_FILE_UEFI "/home/bios/davinci_mini.fd"
#define DEVDRV_DEVICE_FILE_LPM3 "/home/bios/davinci_mini_lpm3.img"
#define DEVDRV_DEVICE_FILE_TEE "/home/bios/davinci_mini_tee.bin"
#define DEVDRV_DEVICE_FILE_CRL "/home/bios/ascend_310.crl"

#define DEVDRV_AUTO_DEVICE_FILE_DTB "/driver/device/davinci_mini_dt.img"
#define DEVDRV_AUTO_DEVICE_FILE_IMAGE "/driver/device/davinci_mini.image"
#define DEVDRV_AUTO_DEVICE_FILE_FS "/driver/device/davinci_mini.cpio.gz"
#define DEVDRV_AUTO_DEVICE_FILE_UEFI "/driver/device/davinci_mini.fd"
#define DEVDRV_AUTO_DEVICE_FILE_LPM3 "/driver/device/davinci_mini_lpm3.img"
#define DEVDRV_AUTO_DEVICE_FILE_TEE "/driver/device/davinci_mini_tee.bin"
#define DEVDRV_AUTO_DEVICE_FILE_CRL "/driver/device/ascend_310.crl"

#define DEVDRV_BLOCKS_NUM 7         /* num of DEVDRV_DEVICE_FILE_* */
#define DEVDRV_BLOCKS_SECOND_FILE 2 /* num of DEVDRV_DEVICE_FILE_* */

#define DEVDRV_BLOCKS_NAME_SIZE 32
#define DEVDRV_BLOCKS_ADDR_PAIR_NUM 3000
#define DEVDRV_BLOCKS_STATIC_NUM 64
#define DEVDRV_BLOCKS_SIZE (1024ul * 1024)
#define DEVDRV_LOAD_FILE_MAX_SIZE (DEVDRV_BLOCKS_SIZE * DEVDRV_BLOCKS_ADDR_PAIR_NUM)
#define DEVDRV_BLOCKS_STATIC_SIZE (DEVDRV_BLOCKS_SIZE * DEVDRV_BLOCKS_STATIC_NUM)

#define DEVDRV_DMA_CACHE_NUM 128
#define DEVDRV_DMA_ALLOC_DEPTH 8

#define DEVDRV_LOAD_FILE_BEGIN 0x1111111111111111ul
#define DEVDRV_NORMAL_BOOT_MODE 0x2222222222222222ul
#define DEVDRV_ABNORMAL_BOOT_MODE 0xFFFFFFFFFFFFFFFFul
#define DEVDRV_SLOW_BOOT_MODE 0x3333333333333333ul
#define DEVDRV_LOAD_SUCCESS 0x55555555u
#define DEVDRV_LOAD_NOTICE 0x5555555555555555ul
#define DEVDRV_LOAD_FINISH 0
#define DEVDRV_SEND_FINISH 0x6666666666666666ul
#define DEVDRV_SEND_PATT_FINISH 0x7777777777777777ul
#define DEVDRV_RECV_FINISH 0x8888888888888888ul
#define DEVDRV_NO_FILE 0X9999999999999999ul

#define DEVDRV_BIOS_VERSION_SUPPORT_REG 0x3dc4c
#define DEVDRV_BIOS_VERSION_SUPPORT_FLAG 0x5aa5dcba
#define DEVDRV_BIOS_VERSION_SUPPORT_CLEAR 0x5aa5dc02
#define DEVDRV_BIOS_BOOTROM_VERSION_REG 0x3dc50
#define DEVDRV_BIOS_XLOADER_VERSION_REG 0x3DC60
#define DEVDRV_BIOS_NVE_VERSION_REG 0x3dc70

#define DEVDRV_LOAD_TIMEOUT 200000ul /* 2s */
#define DEVDRV_LOAD_DELAY 100        /* 100ms */
#define DEVDRV_LOAD_TIMES (DEVDRV_LOAD_TIMEOUT / DEVDRV_LOAD_DELAY)

#define DEVDRV_WAIT_LOAD_FILE_TIME 600

#define DEVDRV_TIMER_SCHEDULE_TIMES 300 /* mini:300s */

#define DEVDRV_TIMER_EXPIRES (1 * HZ)

#define DEVDRV_ALIGN(addr, size) (((addr) + ((size)-1)) & (~((typeof(addr))(size)-1)))

#define DEVDRV_PCIE_CFG_CMDSTS_REG 0X04
#define DEVDRV_PCIE_BAR0_CFG_REG 0X10
#define DEVDRV_PCIE_BAR1_CFG_REG 0X14
#define DEVDRV_PCIE_BAR2_CFG_REG 0X18
#define DEVDRV_PCIE_BAR3_CFG_REG 0X1C
#define DEVDRV_PCIE_BAR4_CFG_REG 0X20
#define DEVDRV_PCIE_BAR5_CFG_REG 0X24
#define DEVDRV_BAR_CFG_OFFSET 32

#define DEVDRV_GET_LOAD_FLAG_SUCCESS 0
#define DEVDRV_GET_LOAD_FLAG_FAILED 1

enum devdrv_load_wait_mode {
    DEVDRV_LOAD_WAIT_INTERVAL = 0x0,
    DEVDRV_LOAD_WAIT_FOREVER
};

struct devdrv_load_addr_pair {
    void *addr;
    dma_addr_t dma_addr;
    u64 size;      /* block size */
    u64 data_size; /* data length is this block */
};

struct devdrv_load_blocks {
    char name[DEVDRV_BLOCKS_NAME_SIZE];
    u64 blocks_num;
    u64 blocks_valid_num;
    struct devdrv_load_addr_pair blocks_addr[DEVDRV_BLOCKS_ADDR_PAIR_NUM];
};

struct devdrv_load_work {
    struct devdrv_pci_ctrl *ctrl;
    struct work_struct work;
};

struct devdrv_agent_load {
    struct device *dev;
    u32 dev_id;
    void __iomem *mem_sram_base;
    struct devdrv_load_blocks *blocks;

    struct timer_list load_timer; /* device os load time out timer */
    int timer_remain;             /* timer_remain <= 0 means time out */
    int timer_expires;

    struct devdrv_load_work load_work;
    atomic_t load_flag;

    int load_vector;
    int load_wait_mode;
    int load_timeout_flag;
};

int devdrv_load_device(struct devdrv_pci_ctrl *pci_ctrl, int device_os_load_irq);
void devdrv_load_exit(struct devdrv_pci_ctrl *pci_ctrl);
void devdrv_notify_blackbox_err(u32 devid, u32 code);

#endif
